Import-Module posh-git
Import-Module oh-my-posh
Set-Theme Paradox


#[========================================ENVIRONMENT START========================================
# Some environment I do not want to set in my system.
# For git could just print the actually utf-8 character.
$env:LANG   = "zh_CN.UTF-8"
$env:LC_ALL = "zh_CN.UTF-8"
#========================================ENVIRONMENT END========================================]

#[========================================COMMON-ALIAS START========================================
Set-Alias -Name ll -Value Get-ChildItem -option AllScope -Scope Global

function Get-ChildItem-With-Wide-Format { Get-ChildItem | Format-Wide -Column 5 }
Set-Alias -Name ls -Value Get-ChildItem-With-Wide-Format -option AllScope -Scope Global

function Get-Content-With-UTF8 { param([Parameter(ValueFromRemainingArguments=$true,Position = 0)][string[]] $paramargs)
        & Get-Content -Encoding UTF8 $paramargs }
Set-Alias -Name cat -Value Get-Content-With-UTF8 -option AllScope -Scope Global
#========================================COMMON-ALIAS END========================================]

#[========================================GIT-ALIAS START========================================
# You can not just alias "git status" to gs, have to create a function at first.
function git-add-all { git add . }
Set-Alias -Name gita -Value git-add-all -option AllScope -Scope Global

function git-status { git status }
Set-Alias -Name gits -Value git-status -option AllScope -Scope Global

function git-commit { param([Parameter(ValueFromRemainingArguments=$true,Position = 0)][string[]] $paramargs)
    & git commit $paramargs }
Set-Alias -Name gitc -Value git-commit -option AllScope -Scope Global

function git-commit-with-add { param([Parameter(ValueFromRemainingArguments=$true,Position = 0)][string[]] $paramargs)
    & git commit -a $paramargs }
Set-Alias -Name gitca -Value git-commit-with-add -option AllScope -Scope Global

function git-pull   { git pull }
Set-Alias -Name gitf -Value git-pull -option AllScope -Scope Global

function git-push   { param([Parameter(ValueFromRemainingArguments=$true,Position = 0)][string[]] $paramargs)
    & git push $paramargs }
Set-Alias -Name gitp -Value git-push -option AllScope -Scope Global

function git-push-master-to-gitee { git push -u gitee master }
Set-Alias -Name gitpe -Value git-push-master-to-gitee -option AllScope -Scope Global

# I spent a lot of time to write this type of function, you can passing variable-length parameters now. See:
# - https://www.reddit.com/r/PowerShell/comments/73wi5e/how_to_write_a_script_that_takes_a_variable/
# - https://stackoverflow.com/questions/3592851/executing-a-command-stored-in-a-variable-from-powershell
function git-diff {
    <#
    .SYNOPSIS
        Compare the files between staged (after `git add`) and not if you don't specific a commit id, otherwise compare the committed and HEAD. And also, if you use `git diff <committed>~ committed`, it will compare the committed with it's ancestor.
    #>
    param(
            [Parameter(ValueFromRemainingArguments=$true,Position = 0)]
            [string[]] $paramargs
         )
    & git diff $paramargs
}
Set-Alias -Name gitd -Value git-diff -option AllScope -Scope Global

function git-diff-staged {
    <#
    .SYNOPSIS
        Compare the files between committed and staged/cached/to be committed.
    #>
    param(
            [Parameter(ValueFromRemainingArguments=$true,Position = 0)]
            [string[]] $paramargs
         )
    & git diff --staged $paramargs
}
Set-Alias -Name gitds -Value git-diff-staged -option AllScope -Scope Global
#function <++> { <++> }
#Set-Alias -Name <++> -Value <++> -option AllScope -Scope Global
#function <++> { <++> }
#Set-Alias -Name <++> -Value <++> -option AllScope -Scope Global
#function <++> { <++> }
#Set-Alias -Name <++> -Value <++> -option AllScope -Scope Global
#========================================GIT-ALIAS END========================================]

#[========================================PATH START========================================
# I don't want to add all these folders or files path to my system environment, so I make some varibles here.
$inboxd = "D:/Inbox"
$otherd = "D:/Other"
$nvimd  = "D:/ProgramFiles/GlobalScoopApps/apps/neovim/current/share/nvim"
# Application settings Backup by git in C disk
$abc    = "C:/AppData/Git/SettingsBackup"
$abd    = "D:/AppData/Git/SettingsBackup"

# This function is common use for me because I use inbox directory as a temporary directory. 
function cd-inbox { cd $inboxd }
Set-Alias -Name cdi -Value cd-inbox -option AllScope -Scope Global
#========================================PATH END========================================]

#[========================================MAKE-LINK START========================================
# There is a powershell wrapper for MKLINK of cmdlet, see https://gist.github.com/jpoehls/2891103. But I found a better one, see https://stackoverflow.com/questions/31863258/how-do-i-create-file-hardlink-in-powershell-on-windows-10
# Or you can also use 
# - ```New-Item -ItemType HardLink -Name CoverageCount.cs -Value ..\..\OPIAspnet5\Models\CoverageCount.cs``` 
# - ```New-Item -ItemType Junction -Name System33 -Value c:\windows\system32```
# See https://stackoverflow.com/questions/31863258/how-do-i-create-file-hardlink-in-powershell-on-windows-10

function New-Hardlink {
    <#
    .SYNOPSIS
        Creates a hard link.
    #>
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $LinkFrom,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $LinkTo
    )
    New-Item -ItemType HardLink -Name $LinkTo -Value $LinkFrom
}
Set-Alias -Name hlink -Value New-Hardlink -option AllScope -Scope Global

function New-Junction {
    <#
    .SYNOPSIS
        Creates a directory junction.
    #>
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $LinkFrom,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $LinkTo
    )
    New-Item -ItemType Junction -Name $LinkTo -Value $LinkFrom
}
Set-Alias -Name jlink -Value New-Junction -option AllScope -Scope Global

function Hardlink-Find{
    <#
    .SYNOPSIS
       Find a hardlink's all files.
    #>
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $FileName
    )
    fsutil.exe hardlink list $FileName
}
Set-Alias -Name hfind -Value Hardlink-Find -option AllScope -Scope Global

function New-Symlink {
    <#
    .SYNOPSIS
        Creates a symbolic link.
    #>
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $Link,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $Target
    )

    Invoke-MKLINK -Link $Link -Target $Target -Symlink
}

function Invoke-MKLINK {
    <#
    .SYNOPSIS
        Creates a symbolic link, hard link, or directory junction.
    #>
    [CmdletBinding(DefaultParameterSetName = "Symlink")]
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $Link,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $Target,

        [Parameter(ParameterSetName = "Symlink")]
        [switch] $Symlink = $true,
        [Parameter(ParameterSetName = "HardLink")]
        [switch] $HardLink,
        [Parameter(ParameterSetName = "Junction")]
        [switch] $Junction
    )

    # Ensure target exists.
    if (-not(Test-Path $Target)) {
        throw "Target does not exist.`nTarget: $Target"
    }

    # Ensure link does not exist.
    if (Test-Path $Link) {
        throw "A file or directory already exists at the link path.`nLink: $Link"
    }

    $isDirectory = (Get-Item $Target).PSIsContainer
    $mklinkArg = ""

    if ($Symlink -and $isDirectory) {
        $mkLinkArg = "/D"
    }

    if ($Junction) {
        # Ensure we are linking a directory. (Junctions don't work for files.)
        if (-not($isDirectory)) {
            throw "The target is a file. Junctions cannot be created for files.`nTarget: $Target"
        }

        $mklinkArg = "/J"
    }

    if ($HardLink) {
        # Ensure we are linking a file. (Hard links don't work for directories.)
        if ($isDirectory) {
            throw "The target is a directory. Hard links cannot be created for directories.`nTarget: $Target"
        }

        $mkLinkArg = "/H"
    }

    # Capture the MKLINK output so we can return it properly.
    # Includes a redirect of STDERR to STDOUT so we can capture it as well.
    $output = cmd /c mklink $mkLinkArg `"$Link`" `"$Target`" 2>&1

    if ($lastExitCode -ne 0) {
        throw "MKLINK failed. Exit code: $lastExitCode`n$output"
    }
    else {
        Write-Output $output
    }
}
#========================================MAKE-LINK END========================================]

#[========================================OTHER START========================================
# Just like `source $profile` in linux, typing `. Reload-Profile` to make it works so that you should not have to restart the terminal when you make some changes in this file.
function Reload-Profile {
    @(
        $Profile.AllUsersAllHosts,
        $Profile.AllUsersCurrentHost,
        $Profile.CurrentUserAllHosts,
        $Profile.CurrentUserCurrentHost
    ) | % {
        if(Test-Path $_){
            Write-Verbose "Running $_"
            . $_
        }
    }    
}
#========================================OTHER END========================================]
